import http from '@ohos.net.http';
import { ApiUtil } from './ApiUtil';
import { ApiResponse } from './ApiResponse';
import { LoggingInterceptor } from './LoggingInterceptor';
import {
  HttpError,
  HttpInterceptor,
  HttpResult,
  RequestChain,
  ResponseChain,
  RespObjectFormat
} from './RequestOptions';

export class HttpApiManager {
  private static instance: HttpApiManager;
  private extraHeaders: Map<string, string> = new Map();
  private interceptors: HttpInterceptor[] = [];
  /**
   * 毫秒
   */
  private timeout: number = 30000; // 默认30秒
  private baseUrl: string = ''; // 添加 baseUrl 字段
  private agent: string = 'apiManager'; // User-Agent
  private maxRetries: number = 1; // 最大重试次数
  private contentType: string = 'application/json; charset=UTF-8'
  private accept: string = 'application/json';
  private expectDataType: http.HttpDataType = http.HttpDataType.OBJECT;
  private respObjectFormat: RespObjectFormat = {
    codeKeyName: 'code',
    meesageKeyName: 'message',
    dataKeyName: 'data'
  };

  private constructor() {
    this.addInterceptor(new LoggingInterceptor());
  }

  /**
   * 单例或者非单例子
   * @param isSingle
   * @returns
   */
  public static getInstance(isSingle: boolean = true): HttpApiManager {

    if (!isSingle) {
      return new HttpApiManager();
    }

    if (!HttpApiManager.instance) {
      HttpApiManager.instance = new HttpApiManager();
    }
    return HttpApiManager.instance;
  }


  private async request(method: http.RequestMethod, urlPath: string,
    data?: string | Object | ArrayBuffer): Promise<ApiResponse> {

    let retryCount = 0;
    let lastError: Error;

    while (retryCount <= this.maxRetries) {

      let httpRequest: http.HttpRequest | null = null;
      try {

        // 创建请求客户端
        httpRequest = http.createHttp();

        // 基本请求配置
        const requestConfig: http.HttpRequestOptions = {
          method: method,
          readTimeout: this.timeout,
          connectTimeout: this.timeout,
          expectDataType: this.expectDataType,
          usingCache: false,
          usingProtocol: http.HttpProtocol.HTTP1_1,
          priority: 1,
        };

        // 拼接完整的请求URL
        const fullUrl = this.baseUrl + urlPath;

        // 构建请求体
        requestConfig.extraData = ApiUtil.dataTryToObject(data);

        // 构建 headers
        let headers = await this.buildHeaders();
        requestConfig.header = headers;

        // 执行拦截器链 - 请求前
        let chain = new RequestChain(fullUrl, method, headers, data, requestConfig);
        for (let interceptor of this.interceptors) {
          chain = await interceptor.onRequest(chain);
        }

        // 发起请求
        const response = await httpRequest.request(chain.url, chain.requestConfig);

        // 执行拦截器链 - 响应后
        let responseChain = new ResponseChain(fullUrl, method, response);
        for (let interceptor of this.interceptors) {
          responseChain = await interceptor.onResponse(responseChain);
        }
        // 响应处理
        let httpResult = this.handleResponse(responseChain.response);
        return httpResult.result;

      } catch (error) {
        // 判断是否需要重试
        if (this.shouldRetry(error) && retryCount < this.maxRetries) {
          retryCount++;
          console.info(`Retrying request (${retryCount}/${this.maxRetries})`);
          // 等待一段时间后重试
          await this.delay(this.getRetryDelay(retryCount));
          continue;
        }
        console.error(`Api Error (attempt ${retryCount + 1}/${this.maxRetries + 1}): ${error}`);
        return new ApiResponse(error.code, error.message, null);
      } finally {
        // 清理请求对象
        if (httpRequest) {
          httpRequest.destroy();
        }
      }
    }

    throw lastError;

  }


  // 判断是否需要重试
  private shouldRetry(error: any): boolean {
    // 网络错误、超时等情况下重试
    if (error instanceof HttpError) {
      return error.code === -200 || // 网络断开
        error.code === 408 || // 请求超时
        error.code === 500 || // 服务器错误
        error.code === 502 || // 网关错误
        error.code === 503 || // 服务不可用
        error.code === 504; // 网关超时
    }
    return false;
  }

  // 获取重试延迟时间（指数退避）
  private getRetryDelay(retryCount: number): number {
    return Math.min(1000 * Math.pow(2, retryCount - 1), 10000);
  }

  // 延迟函数
  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  // 设置最大重试次数
  setMaxRetries(retries: number): HttpApiManager {
    this.maxRetries = retries;
    return this;
  }

  // 设置 User-Agent
  setAgent(agent: string): HttpApiManager {
    this.agent = agent;
    return this;
  }

  // 设置 contentType
  setContentType(contentType: string): HttpApiManager {
    this.contentType = contentType;
    return this;
  }

  // 设置 accept
  setAccept(accept: string): HttpApiManager {
    this.accept = accept;
    return this;
  }

  // 设置 expectDataType
  setExpectDataType(expectDataType: http.HttpDataType): HttpApiManager {
    this.expectDataType = expectDataType;
    return this;
  }

  // 设置 respObjectFormat
  setRespObjectFormat(respObjectFormat: RespObjectFormat): HttpApiManager {
    this.respObjectFormat = respObjectFormat;
    return this;
  }

  // 设置超时时间
  setTimeout(milliseconds: number): HttpApiManager {
    this.timeout = milliseconds;
    return this;
  }

  // 添加请求头
  addHeader(key: string, value: string): HttpApiManager {
    this.extraHeaders.set(key, value);
    return this;
  }

  // 移除请求头
  removeHeader(key: string): HttpApiManager {
    this.extraHeaders.delete(key);
    return this;
  }

  // 添加拦截器
  addInterceptor(interceptor: HttpInterceptor): HttpApiManager {
    this.interceptors.push(interceptor);
    return this;
  }

  // 设置 baseUrl
  public setBaseUrl(baseUrl: string): HttpApiManager {
    this.baseUrl = baseUrl;
    return this;
  }

  // GET请求
  async get(url: string): Promise<ApiResponse> {
    return this.request(http.RequestMethod.GET, url, null);
  }

  // POST请求
  async post(url: string, data?: any): Promise<ApiResponse> {
    return this.request(http.RequestMethod.POST, url, data);
  }

  // PUT请求
  async put(url: string, data?: any): Promise<ApiResponse> {
    return this.request(http.RequestMethod.PUT, url, data);
  }

  // DELETE请求
  async delete(url: string): Promise<ApiResponse> {
    return this.request(http.RequestMethod.DELETE, url, null);
  }

  private async buildHeaders(additionalHeaders?: Map<string, string>): Promise<Record<string, string>> {
    let headerObj: Record<string, string> = await this.buildDefaultHeaders();

    this.extraHeaders.forEach((value, key) => {
      headerObj[key] = value;
    });

    if (additionalHeaders) {
      additionalHeaders.forEach((value, key) => {
        headerObj[key] = value;
      });
    }

    return headerObj;
  }

  /**
   * 默认header
   * @returns
   */
  private async buildDefaultHeaders(): Promise<Record<string, string>> {
    let headerObj: Record<string, string> = {
      'Content-Type': this.contentType,
      'Accept': this.accept,
      'Connection': 'keep-alive',
      'User-Agent': this.agent,
      'channel': 'ohos'
    };
    return headerObj;
  }

  private handleResponse(response: http.HttpResponse): HttpResult {
    if (response.responseCode >= 200 && response.responseCode < 300) {
      // 解析并提取 result, 正常输出为 object ：{"code":0, "message":"success", "data" : any}
      const result = response.result as any;

      // 获取 obj 中的值
      if (result instanceof Object) {
        console.error('ApiResult: ' + JSON.stringify(result));
        const code = result[this.respObjectFormat.codeKeyName] as any;
        const message = result[this.respObjectFormat.meesageKeyName] as any;
        const data = result[this.respObjectFormat.dataKeyName] as any;

        if (code === 0) {
          return {
            success: true,
            result: new ApiResponse(code, message, data),
            httpResponse: response
          };
        } else {
          return {
            success: false,
            result: new ApiResponse(code, message, data),
            httpResponse: response,
          };
        }
      } else if (result instanceof String) {
        return {
          success: true,
          result: new ApiResponse(response.responseCode, response.responseCode, response.result),
          httpResponse: response
        };
      } else if (result instanceof ArrayBuffer) {
        return {
          success: true,
          result: new ApiResponse(response.responseCode, response.responseCode, response.result),
          httpResponse: response
        };
      } else {
        throw new HttpError(
          -300,
          'Unknow data type',
          result
        )
      }

    } else if (response.responseCode >= 500 && response.responseCode < 600) {
      throw new HttpError(
        500,
        'Server error'
      )
    } else if (response.responseCode >= 400 && response.responseCode < 500) {
      throw new HttpError(
        400,
        'no uri'
      )
    } else {
      throw new HttpError(
        response.responseCode,
        'extra error'
      )
    }
  }
}
